﻿using System;
using System.Collections.Generic;
using System.Threading;
using PSE.Deployment.Engine;
using PSE.Deployment.Engine.CustomExceptions;
using PSE.Deployment.Engine.Interfaces;
using PSE.Deployment.SetupBase;
using Sinacor.Deployment.Setup.Configuration.Enums;
using Sinacor.Deployment.Setup.DataAccess;
using Sinacor.Deployment.Setup.Main;
using Sinacor.Deployment.Setup.Parameter;
using PSE.Deployment.Util;

namespace Sinacor.Deployment.Setup.Uninstall.DataBase.Steps
{
    public class CompanyDropSchema : BaseStep
    {
        private Company Company { get; set; }
        private Configuration.Script CompanyCommands { get; set; }
        private List<string> _progressDescriptions;
        private bool _install = false;

        public CompanyDropSchema(IStepGroup parent, Company company, bool install)
            : base(parent)
        {
            _install = install;

            this.Id = "DataBase.CompanyDropSchema." + company.Id.ToString();
            this.Description = string.Format(StepDescriptions.COMPANY_DROP_SCHEMA, company.Name);

            this.ErrorBehavior = PSE.Deployment.Engine.Enums.StepErrorBehavior.Ignore;
            this.NavigationBehavior = PSE.Deployment.Engine.Enums.StepNavigationBehavior.NextCancel;

            Company = company;

            _progressDescriptions = new List<string>();

            CompanyCommands = SetupMainFactory.GetInstance<SinacorMain>().Configuration.Scripts.Scripts.Find(x => x.Schema == Sinacor.Deployment.Setup.Configuration.Enums.SchemaType.Company && x.Type == Sinacor.Deployment.Setup.Configuration.Enums.ScriptType.Drop);
            ResetProgress(CompanyCommands.Commands.Count);
        }

        public override void Execute()
        {
            ResetProgress(CompanyCommands.Commands.Count);

            MultipleException multipleException = new MultipleException("Ocorreram erros ao executar os comandos");

            using (OracleDataBase db = new OracleDataBase(SetupMainFactory.GetInstance<SinacorMain>().Parameter.DataBase.ConnectionInfo.User, EncryptDecrypt.Decrypt(SetupMainFactory.GetInstance<SinacorMain>().Parameter.DataBase.ConnectionInfo.Password), SetupMainFactory.GetInstance<SinacorMain>().Parameter.DataBase.ConnectionInfo.TNSName, SetupMainFactory.GetInstance<SinacorMain>().Parameter.DataBase.ConnectionInfo.IsEncrypted))
            {
                foreach (Configuration.Command command in CompanyCommands.Commands)
                {
                    if (this.IsStopped())
                        break;

                    string stringCommand = command.StringCommand.Replace("[COMPANYUSER]", this.Company.Login).Replace("[SYSTEMUSER]", SetupMainFactory.GetInstance<SinacorMain>().Parameter.DataBase.ConnectionInfo.User);

                    string progressDescription = DataBaseGroup.GetProgressDescription(stringCommand);

                    this.IncrementProgress(progressDescription);

                    try
                    {
                        if (command.ExecutionSchema == SchemaType.Company)
                            db.ExecuteNonQuery(this.Company.Id, stringCommand);
                        else if (command.ExecutionSchema == SchemaType.System)
                            db.ExecuteNonQuery(stringCommand);
                    }
                    catch (Exception ex)
                    {
                        multipleException.InnerExceptions.Add(new DataBaseException("Erro ao executar o comando", stringCommand, ex));
                    }

                    if (!_progressDescriptions.Contains(progressDescription))
                        _progressDescriptions.Add(progressDescription);
                }
            }

            if (multipleException.InnerExceptions.Count > 0)
                SetupMainFactory.GetInstance<SinacorMain>().WriteStepLog(this, "finalizado com erros.", multipleException);
        }

        public override void Undo()
        {
            if (_install)
            {
                for (int i = _progressDescriptions.Count - 1; i >= 0; i--)
                {
                    this.DecrementProgress(_progressDescriptions[i]);

                    _progressDescriptions.RemoveAt(i);

                    Thread.Sleep(20);
                }
            }
        }
    }
}
